package opt;

import java.math.BigDecimal;
import java.util.Random;
import java.util.Vector;

import util.Connections;
import util.ContributingSensors;

import ns2.Field;

import ids.ProbeSensor;
import ids.Sensor;

public class FitnessFunction {

	public float rawfitness;
	public float falsenegative;
	public float falsepositive;
	public float allTraffic;
	public float normalTraffic;
	public int visiableAttacks;
	public int detectedAttacks;
	public int allAlarms;
	public int falseAlarms;
	public float staticInfo;
	public float positivepredictiverate;
	public int nContributingSensors;

	private boolean contributionChecked;
	private boolean[] contributing;

	public FitnessFunction() {
		this.falsenegative = 0.05f;
		this.falsepositive = 0.001f;
		this.contributionChecked = false;
	}

	public float evaluate(Vector<Sensor> sensors) {
		this.reset();
		if (!contributionChecked)
			nContributingSensors = sensors.size();

		Connections connections = new Connections();
		Random rnd = new Random(1234);

		float n1 = 0;
		float n2 = 0;
		float n3 = 0;
		float bandwidth = 0;
		for (int i = 0; i < sensors.size(); i++) {
			connections.addAll(sensors.elementAt(i).location.connections);
			n1 = n1 + sensors.elementAt(i).efficiency;
			// * sensors.elementAt(i).location.getRiskProfile();
			n2 = n2 + sensors.elementAt(i).deploymentCost
					+ sensors.elementAt(i).location.getDisruptionCost();
			n3 = n3 + sensors.elementAt(i).monitoringCost
					* sensors.elementAt(i).location.getLoadFactor();
			bandwidth += sensors.elementAt(i).location.getLoadFactor();
		}
		staticInfo = n1 / (n2 + n3);

		Vector<Connections> groupBySources = connections.sort(Field.Src_addr);
		for (int i = 0; i < groupBySources.size(); i++) {
			if (groupBySources.elementAt(i).size() >= ProbeSensor.lower_threshold) {
				visiableAttacks += groupBySources.elementAt(i).size();
			}
		}

		// normalTraffic = (connections.size() - allAttacks) * 1000;
		normalTraffic = bandwidth * 1000;
		allTraffic = normalTraffic + visiableAttacks;

		int counter1 = 0;
		int counter2 = 0;
		while (counter1 < visiableAttacks) {
			counter1++;
			if (rnd.nextFloat() >= falsenegative) {
				detectedAttacks++;
			}
		}
		while (counter2 < normalTraffic) {
			counter2++;
			if (rnd.nextFloat() <= falsepositive) {
				falseAlarms++;
			}
		}
		allAlarms = detectedAttacks + falseAlarms;

		if (allAlarms == 0)
			positivepredictiverate = 0;
		else
			positivepredictiverate = (float) detectedAttacks
					/ (float) allAlarms;
		BigDecimal bd = new BigDecimal(positivepredictiverate);
		positivepredictiverate = bd.setScale(4, BigDecimal.ROUND_HALF_UP)
				.floatValue();

		rawfitness = (float) visiableAttacks * staticInfo
				* (float) nContributingSensors / (float) sensors.size();

		return rawfitness;
	}

	public String evaluateAndPrint(Vector<Sensor> sensors) {
		this.checkContribution(sensors);
		this.evaluate(sensors);

		StringBuffer result = new StringBuffer();
		result.append("\nOverall Fitness: " + rawfitness);
		result.append("\nDetected Attacks: " + detectedAttacks);
		result.append("\nVisiable Attacks:" + visiableAttacks);
		result.append("\nAll Alarms: " + allAlarms);
		result.append("\nFalse Alarms: " + falseAlarms);
		result.append("\nPositive Predictive Rate: " + positivepredictiverate);
		result.append("\nNormal Traffic: " + normalTraffic);
		result.append("\nContributing Sensors: " + nContributingSensors);
		result.append("\nContributing Sensors are placed on nodes: ");
		for (int i = 0; i < contributing.length; i++) {
			if (contributing[i]) {
				result.append(sensors.elementAt(i).location.id + " ");
			}
		}
		result.append("\n");
		return result.toString();
	}

	public void checkContribution(Vector<Sensor> sensors) {
		ContributingSensors cs = new ContributingSensors(sensors);
		nContributingSensors = cs.getNumberOfContributingSensors();
		contributionChecked = true;
		contributing = cs.contributing;
	}

	private void reset() {
		this.rawfitness = 0;
		this.allTraffic = 0;
		this.normalTraffic = 0;
		this.visiableAttacks = 0;
		this.detectedAttacks = 0;
		this.allAlarms = 0;
		this.falseAlarms = 0;
		this.staticInfo = 0;
		this.positivepredictiverate = 0;
	}
}